package io.gitee.tziye.core.bloom;

import io.gitee.tziye.core.instance.DefaultRenaiClient;
import io.gitee.tziye.jdbc.JdbcProxy;
import io.vavr.Tuple2;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class DefaultBloomOperator extends BloomOperator {

    private final JdbcProxy jdbcProxy;

    public DefaultBloomOperator(DefaultRenaiClient renaiClient) {
        super(renaiClient);
        jdbcProxy = renaiClient.getJdbcProxy();
    }

    @Override
    public <T> boolean put(String module, T value) {
        assert StringUtils.isNotBlank(module) && value != null;
        List<Tuple2<Integer, Long>> hashList = GuavaBloomFilter.calculate(value);
        String sql = "INSERT INTO renai_bloom_filter(module, %s) VALUES (?, %s) ON DUPLICATE KEY UPDATE %s, update_time = NOW()";
        String s1 = hashList.stream().map(t -> "h" + t._1).collect(Collectors.joining(","));
        // 由于MySQL执行或操作时，会将有符号数转为无符号数，因此字段设计成BIGINT UNSIGNED，且插入时要与0执行或操作转为无符号数
        String s2 = hashList.stream().map(t -> "0 | " + t._2).collect(Collectors.joining(","));
        String s3 = hashList.stream().map(t -> String.format("h%s = h%s | %s", t._1, t._1, t._2))
                .collect(Collectors.joining(","));
        sql = String.format(sql, s1, s2, s3);
        return jdbcProxy.update(sql, module) > 0;
    }

    @Override
    public <T> boolean mightContain(String module, T value) {
        assert StringUtils.isNotBlank(module) && value != null;
        List<Tuple2<Integer, Long>> hashList = GuavaBloomFilter.calculate(value);
        String sql = "SELECT id FROM renai_bloom_filter WHERE module = ? AND %s";
        List<String> s = new ArrayList<>();
        hashList.forEach(t -> s.add(String.format(" h%s & %s > 0 ", t._1, t._2)));
        sql = String.format(sql, String.join("AND", s));
        return CollectionUtils.isNotEmpty(jdbcProxy.queryForList(sql, Integer.class, module));
    }

    @Override
    public boolean delete(String module) {
        String sql = "DELETE FROM renai_bloom_filter WHERE module = ?";
        return jdbcProxy.update(sql, module) > 0;
    }

}
